package utils

import (
	"math"
	"regexp"
	"strconv"
	"strings"
)

// CompareVersion 版本比较
// -1:	ver1 < ver2
// 0:	ver1 == ver2
// 1:	ver1 > ver2
func CompareVersion(ver1, ver2 string, ignoreCase ...bool) int {
	const (
		LT = -1
		EQ = 0
		GT = 1
	)

	const ANY = "x"

	if len(ignoreCase) > 0 && ignoreCase[0] {
		ver1 = strings.ToUpper(ver1)
		ver2 = strings.ToUpper(ver2)
	}

	if ver1 == ver2 {
		return EQ
	} else if len(ver1) > 0 && len(ver2) == 0 {
		return GT
	} else if len(ver1) == 0 && len(ver2) > 0 {
		return LT
	}

	intCompare := func(i1, i2 int) int {
		if i1 < i2 {
			return LT
		} else if i1 == i2 {
			return EQ
		} else {
			return GT
		}
	}

	stringCompare := func(s1, s2 string) int {
		if s1 != s2 {
			for i := 0; i < len(s1) && i < len(s2); i++ {
				if s1[i] < s2[i] {
					return LT
				} else if s1[i] > s2[i] {
					return GT
				} else {
					v1, err1 := strconv.Atoi(s1[i+1:])
					v2, err2 := strconv.Atoi(s2[i+1:])
					if err1 == nil && err2 == nil {
						return intCompare(v1, v2)
					}
				}
			}
		}

		return EQ
	}

	ver1Slice := splitVersion(ver1)
	ver2Slice := splitVersion(ver2)
	v1Size := len(ver1Slice)
	v2Size := len(ver2Slice)
	minSize := int(math.Min(float64(v1Size), float64(v2Size)))

	for i := 0; i < minSize; i++ {
		if ver1Slice[i] == ANY || ver2Slice[i] == ANY || ver1Slice[i] == ver2Slice[i] {
			continue
		}

		v1, err1 := strconv.Atoi(ver1Slice[i])
		v2, err2 := strconv.Atoi(ver2Slice[i])
		if err1 != nil || err2 != nil {
			// string compare
			return stringCompare(ver1Slice[i], ver2Slice[i])
		} else {
			// number compare
			return intCompare(v1, v2)
		}
	}

	return EQ
}

func splitVersion(version string) []string {
	return regexp.MustCompile(`[\.\-_]`).Split(version, -1)
}
